const beam = @import("beam");
const e = @import("erl_nif");
const nif = @import("nif");
const Allocator = @import("std").mem.Allocator;
const Resource = beam.Resource;
const root = @This();
const threads = beam.threads;
const builtin = @import("builtin");

<%= for nif <- @nifs do %>
<%= Nif.render_zig(nif) %>
<% end %>

<%= Resources.render(resources: @resources, module: @module) %>

// this will be filled out later.
fn load(env: beam.env, priv_data: [*c]?*anyopaque, load_info: e.ErlNifTerm) callconv(.c) c_int {
    defer load_resources(env);
    <%= if @callbacks[:on_load] do %>
      <%= render_on_load(assigns) %>
    <% else %>
    _ = priv_data;
    _ = load_info;
    return 0;
    <% end %>
}

var exported_nifs = [_]e.ErlNifFunc{<%= table_entries(@nifs) %>};

fn upgrade(env: beam.env, priv_data: [*c]?*anyopaque, old_priv_data: [*c]?*anyopaque, load_info: e.ErlNifTerm) callconv(.c) c_int {
    defer load_resources(env);
    <%= if @callbacks[:on_upgrade] do %>
      <%= render_on_upgrade(@sema.callbacks) %>
    <% else %>
    _ = priv_data;
    _ = old_priv_data;
    _ = load_info;
    return 0;
    <% end %>
}

<%= if @callbacks[:on_unload], do: render_on_unload(@sema.callbacks) %>

const entry = e.ErlNifEntry{
    .major = <%= nif_version(:major) %>,
    .minor = <%= nif_version(:minor) %>,
    .name = "<%= @module %>",
    .num_of_funcs = exported_nifs.len,
    .funcs = &exported_nifs,
    .load = load,
    .reload = null,   // never supported as of OTP 20
    .upgrade = <%= if @callbacks[:on_upgrade] do %> upgrade <% else %> beam.loader.blank_upgrade <% end %>,
    .unload = <%= if @callbacks[:on_unload] do %> unload <% else %> beam.loader.blank_unload <% end %>,
    .vm_variant = "beam.vanilla",
    .options = 1,
    .sizeof_ErlNifResourceTypeInit = @sizeOf(e.ErlNifResourceTypeInit),
    .min_erts = "erts-<%= :erlang.system_info(:version)%>"
};

<% # todo: use a better target feature %>
<%= case :os.type() do %>
<% {_, :nt} -> %>

const string = @cImport(@cInclude("string.h"));

export var WinDynNifCallbacks: e.TWinDynNifCallbacks = undefined;

export fn nif_init(callbacks: [*c]e.TWinDynNifCallbacks) callconv(.winapi) [*c]const e.ErlNifEntry {
    _ = string.memcpy(&WinDynNifCallbacks, callbacks, @sizeOf(e.TWinDynNifCallbacks));
    return &entry;
}
<% _ -> %>
export fn nif_init() *const e.ErlNifEntry {
    return &entry;
}
<% end %>

fn sectionName() []const u8 {
    return switch (builtin.target.ofmt) {
        .macho => "__DATA,__sema", // Mach-O requires SEGMENT,SECTION
        else => ".sema",           // ELF/COFF-style single name
    };
}

export const sema: [<%= byte_size(@sema_json) %>:0] u8 linksection(sectionName()) = "<%= escape(@sema_json) %>".*;
